package com.kabao.javafx;

import com.leewyatt.rxcontrols.controls.RXAudioSpectrum;
import com.leewyatt.rxcontrols.controls.RXLrcView;
import com.leewyatt.rxcontrols.controls.RXMediaProgressBar;
import com.leewyatt.rxcontrols.controls.RXToggleButton;
import com.leewyatt.rxcontrols.pojo.LrcDoc;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Bounds;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioSpectrumListener;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;

public class PlayerController {

    @FXML
    private ResourceBundle resources;

    @FXML
    private URL location;

    @FXML
    private StackPane soundBtn;
    @FXML
    private StackPane skinBtn;

    @FXML
    private ToggleButton playBtn;

    @FXML
    private AnchorPane drawerPane;

    @FXML
    private BorderPane sliderPane;
    private Timeline showAnim;
    private Timeline hideAnim;
    private ContextMenu soundPopup;
    private ContextMenu skinPopup;

    @FXML
    private ListView<File> listView;

    @FXML
    private RXAudioSpectrum audioSpectrum;

    @FXML
    private RXMediaProgressBar progressBar;

    @FXML
    private RXLrcView lrcView;

    @FXML
    private Label timeLabel;


    private MediaPlayer player;
    private Slider soundSlider;
    private Label soundNumLabel;

    //设置频谱可视化
    private final AudioSpectrumListener audioSpectrumListener = new AudioSpectrumListener() {
        @Override
        public void spectrumDataUpdate(double timestamp, double duration, float[] magnitudes, float[] phases) {
            audioSpectrum.setMagnitudes(magnitudes);
        }
    };
    private final ChangeListener<Duration> durationChangeListener = (observable1, oldDuration, newDuration) -> {
        progressBar.setCurrentTime(newDuration);
        changeTimeLabel(newDuration);
    };
    private final float[] magnitudes = new float[128];

    //日期格式化
    private final SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");

    @FXML
    void onHideSliderPaneAction(MouseEvent event) {
        showAnim.stop();
        hideAnim.play();
    }

    private void changeTimeLabel(Duration nv1){
        String currentTime = sdf.format(nv1.toMillis());
        String bufferedTimer = sdf.format(player.getBufferProgressTime().toMillis());
        timeLabel.setText(currentTime + "/" + bufferedTimer);
    }

    @FXML
    void onSoundPopupAction(MouseEvent event) {
        Bounds bounds = soundBtn.localToScreen(soundBtn.getBoundsInLocal());
        soundPopup.show(findStage(), bounds.getMinX() - 20, bounds.getMinY() - 255);
    }

    @FXML
    void onSkinPopupAction(MouseEvent event) {
        Bounds bounds = skinBtn.localToScreen(skinBtn.getBoundsInLocal());
        skinPopup.show(findStage(), bounds.getMaxX() - 135, bounds.getMaxY() + 10);
    }

    private Stage findStage() {
        Stage stage = (Stage) drawerPane.getScene().getWindow();
        return stage;
    }

    @FXML
    void onShowSliderPaneAction(MouseEvent event) {
        drawerPane.setVisible(true);
        hideAnim.stop();
        showAnim.play();
    }

    @FXML
    void onCloseAction(MouseEvent event) {
        Platform.exit();
    }

    @FXML
    void onFullAction(MouseEvent event) {
        Stage stage = (Stage) drawerPane.getScene().getWindow();
        stage.setFullScreen(!stage.isFullScreen());
    }


    @FXML
    void onMiniAction(MouseEvent event) {
        Stage stage = (Stage) drawerPane.getScene().getWindow();
        stage.setIconified(true);
    }

    /**
     * 添加歌曲
     *
     * @param event
     */
    @FXML
    void onAddMusicAction(MouseEvent event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("mp3", "*.mp3"));
        List<File> fileList = fileChooser.showOpenMultipleDialog(findStage());
        ObservableList<File> items = listView.getItems();
        if (!Objects.isNull(fileList)) {
            fileList.forEach(file -> {
                if (!items.contains(file)) {
                    items.add(file);
                }
            });
        }

    }

    @FXML
    void onPlayAction(MouseEvent event) {
        if(Objects.nonNull(player)){
            if (playBtn.isSelected()) {
                player.play();
            } else {
                player.pause();
            }
        }else{
            if(listView.getItems().size() !=0){
                listView.getSelectionModel().select(0);
            }
        }
    }

    @FXML
    void onPlayNextAction(MouseEvent event) {
        onPlayNext();
    }

    private void onPlayNext() {
        int size = listView.getItems().size();
        if(size <2){
            return;
        }
        int index = listView.getSelectionModel().getSelectedIndex();
        //如果是最后一首,那么下一首就是第一首
        index = (index == size - 1)?0:index+1;
        listView.getSelectionModel().select(index);
    }

    @FXML
    void onPlayPrevAction(MouseEvent event) {
        int size = listView.getItems().size();
        if(size <2){
            return;
        }
        int index = listView.getSelectionModel().getSelectedIndex();
        //如果是最后一首歌, 那么下一首歌曲就是播放第一首歌曲
        index = (index == 0)?size - 1:index - 1;
        listView.getSelectionModel().select(index);
    }

    @FXML
    void initialize() {
        initAnim();
        initSoundPopup();
        initSkinPopup();
        initListView();
        Arrays.fill(magnitudes,-60.0f);
        initProgressBar();
    }

    /**
     * 初始化listview
     */
    private void initListView() {
        listView.setCellFactory(fileListView -> new MusicListCell());
        listView.getSelectionModel().selectedItemProperty().addListener((observable, oldFile, newFile) -> {
            if (newFile != null) {
                //清除player 中的数据
                if (player != null) {
                    disposeMediaPlayer();
                }
                //播放歌曲
                player = new MediaPlayer(new Media((newFile.toURI().toString())));
                player.setVolume(soundSlider.getValue() / 100);

                //设置歌词
                String lrcPath = newFile.getAbsolutePath().replaceAll("mp3$", "lrc");
                File lcrFile = new File(lrcPath);
                if (lcrFile.exists()) {
                    try {
                        byte[] bytes = Files.readAllBytes(lcrFile.toPath());
                        //解析歌词
                        lrcView.setLrcDoc(LrcDoc.parseLrcDoc(new String(bytes, com.leewyatt.player.EncodingDetect.detect(bytes))));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //设置歌词进度,和歌曲的播放进度绑定
                lrcView.currentTimeProperty().bind(player.currentTimeProperty());
                //设置频谱可视化
                player.setAudioSpectrumListener(audioSpectrumListener);
                //设置进度条的总时长
                progressBar.durationProperty().bind(player.getMedia().durationProperty());
                //播放器的进度修改监听器
                player.currentTimeProperty().addListener(durationChangeListener);
                //如果播放完当前歌曲,自动播放下一曲
                player.setOnEndOfMedia(this::onPlayNext);
                playBtn.setSelected(true);
                player.play();
            }else{
                disposeMediaPlayer();
            }
        });
    }

    /**
     * 销毁mediaPlayer
     */
    private void disposeMediaPlayer() {
        player.stop();
        lrcView.setLrcDoc(null);
        lrcView.currentTimeProperty().unbind();
        lrcView.setCurrentTime(Duration.ZERO);
        player.setAudioSpectrumListener(null);
        progressBar.durationProperty().unbind();
        progressBar.setCurrentTime(Duration.ZERO);
        player.currentTimeProperty().removeListener(durationChangeListener);
        playBtn.setSelected(false);
        timeLabel.setText("00:00 / 00:00");
        audioSpectrum.setMagnitudes(magnitudes);
        player.dispose();
        player = null;
    }

    private void initProgressBar() {
        EventHandler<MouseEvent> progressBarHandler = event -> {
            if (player != null) {
                player.seek(progressBar.getCurrentTime());
                changeTimeLabel(progressBar.getCurrentTime());
            }
        };
        //进度条的调整
        progressBar.setOnMouseClicked(progressBarHandler);
        progressBar.setOnMouseDragged(progressBarHandler);
    }

    /**
     * 初始化皮肤弹窗
     */
    private void initSkinPopup() {
        skinPopup = new ContextMenu(new SeparatorMenuItem());
        Parent skinRoot = null;
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/skin.fxml"));
            skinRoot = fxmlLoader.load();
            ObservableMap<String, Object> namespace = fxmlLoader.getNamespace();
            ToggleGroup skinGroup = (ToggleGroup) namespace.get("skinGroup");
            skinGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) ->  {
                RXToggleButton skinBtn = (RXToggleButton) newValue;
                String skinName = skinBtn.getText();
                String url = "/css/" + skinName + ".css";
                String skinUrl = getClass().getResource(url).toExternalForm();
                drawerPane.getScene().getRoot().getStylesheets().setAll(skinUrl);
                skinPopup.getScene().getRoot().getStylesheets().setAll(skinUrl);
                soundPopup.getScene().getRoot().getStylesheets().setAll(skinUrl);
            });

        } catch (IOException e) {
            e.printStackTrace();
        }
        skinPopup.getScene().setRoot(skinRoot);
    }

    private void initSoundPopup() {
        soundPopup = new ContextMenu(new SeparatorMenuItem());
        Parent soundRoot = null;
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/sound.fxml"));
            soundRoot = fxmlLoader.load();
            ObservableMap<String, Object> namespace = fxmlLoader.getNamespace();
            soundSlider = (Slider) namespace.get("soundSlider");
            soundNumLabel = (Label) namespace.get("soundNum");
            //soundNumLabel 和soundSlider 关联
            soundNumLabel.textProperty().bind(soundSlider.valueProperty().asString("%.0f%%"));
            //声音滑块改变时,改变player的音量
            soundSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
                if (player != null) {
                    player.setVolume(newValue.doubleValue() / 100);
                }
            });

        } catch (IOException e) {
            e.printStackTrace();
        }
        soundPopup.getScene().setRoot(soundRoot);
    }

    private void initAnim() {
        showAnim = new Timeline(new KeyFrame(Duration.millis(300), new KeyValue(sliderPane.translateXProperty(), 0)));
        hideAnim = new Timeline(new KeyFrame(Duration.millis(300), new KeyValue(sliderPane.translateXProperty(), 300)));
        hideAnim.setOnFinished(e -> {
            drawerPane.setVisible(false);
        });
    }

}
